package com.luo.d3s.light.mybatis.ec.application.service.impl;

import com.luo.d3s.core.application.assmebler.BaseAssembler;
import com.luo.d3s.core.application.dto.Response;
import com.luo.d3s.core.application.dto.SingleResponse;
import com.luo.d3s.core.util.validation.Validates;
import com.luo.d3s.light.mybatis.ec.application.assembler.GoodsAssembler;
import com.luo.d3s.light.mybatis.ec.application.dto.command.GoodsCreateCommand;
import com.luo.d3s.light.mybatis.ec.application.dto.command.GoodsModifyCommand;
import com.luo.d3s.light.mybatis.ec.application.dto.vo.GoodsVo;
import com.luo.d3s.light.mybatis.ec.application.service.GoodsCommandService;
import com.luo.d3s.light.mybatis.ec.domain.goods.Goods;
import com.luo.d3s.light.mybatis.ec.domain.goods.GoodsRepository;
import com.luo.d3s.light.mybatis.ec.domain.goods.GoodsStatus;
import com.luo.d3s.light.mybatis.ec.domain.goods.WeightUnit;
import com.luo.d3s.light.mybatis.ec.domain.specification.CategoryExistSpecification;
import com.luo.d3s.light.mybatis.ec.domain.specification.GoodsShelvedNotExistSpecification;
import com.luo.d3s.light.mybatis.ec.domain.specification.GoodsTagExistSpecification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 商品命令处理服务实现类
 *
 * @author luohq
 * @date 2023-01-04 17:06
 */
@Service
public class GoodsCommandServiceImpl implements GoodsCommandService {

    private GoodsRepository goodsRepository;

    private CategoryExistSpecification categoryExistSpecification;
    private GoodsShelvedNotExistSpecification goodsShelvedNotExistSpecification;
    private GoodsTagExistSpecification goodsTagExistSpecification;

    public GoodsCommandServiceImpl(GoodsRepository goodsRepository,
                                   CategoryExistSpecification categoryExistSpecification,
                                   GoodsShelvedNotExistSpecification goodsShelvedNotExistSpecification,
                                   GoodsTagExistSpecification goodsTagExistSpecification) {
        this.goodsRepository = goodsRepository;
        this.categoryExistSpecification = categoryExistSpecification;
        this.goodsShelvedNotExistSpecification = goodsShelvedNotExistSpecification;
        this.goodsTagExistSpecification = goodsTagExistSpecification;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SingleResponse<GoodsVo> createGoods(GoodsCreateCommand goodsCreateCommand) {
        //创建商品实体
        Goods goods = GoodsAssembler.createGoods(goodsCreateCommand);
        //验证新增商品分类是否存在
        this.categoryExistSpecification.isSatisfiedBy(goods.getCategoryId());
        //验证商品标签是否存在
        this.goodsTagExistSpecification.isSatisfiedBy(goods.getTags());
        //保存商品
        goods = this.goodsRepository.save(goods);
        //转换GoodsDto
        return SingleResponse.of(BaseAssembler.convert(goods, GoodsVo.class));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Response modifyGoods(GoodsModifyCommand goodsModifyCommand) {
        //验证待修改商品是否存在
        Goods goods = this.goodsRepository.findById(goodsModifyCommand.getId());
        Validates.notNull(goods, "goods does not exist");
        //验证待修改商品分类是否存在
        this.categoryExistSpecification.isSatisfiedBy(goodsModifyCommand.getCategoryId());
        //验证商品标签是否存在
        this.goodsTagExistSpecification.isSatisfiedBy(goods.getTags());
        //修改基础信息
        goods.modifyBasicInfo(
                goodsModifyCommand.getCategoryId(),
                goodsModifyCommand.getGoodsName(),
                goodsModifyCommand.getManufactureDate(), goodsModifyCommand.getExpirationDate(),
                goodsModifyCommand.getGoodsWeight(), WeightUnit.of(goodsModifyCommand.getGoodsWeightUnit()),
                goodsModifyCommand.getGoodsDesc(),
                goodsModifyCommand.getGoodsPrice(),
                goodsModifyCommand.getTagIds()
        );
        //保存商品
        this.goodsRepository.save(goods);
        return Response.buildSuccess();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Response removeGoods(List<Long> goodsIds) {
        //验证是不存在已上架状态的商品才可批量删除
        this.goodsShelvedNotExistSpecification.isSatisfiedBy(goodsIds);
        //批量删除商品
        this.goodsRepository.removeByIds(goodsIds);
        return Response.buildSuccess();
    }

    /**
     * 上架商品 - 事务脚本实现方式
     *
     * @param goodsIds 商品ID列表
     * @return 响应结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Response shelveGoods(List<Long> goodsIds) {
        //批量更新商品状态为已上架
        this.goodsRepository.batchModifyGoodsStatus(goodsIds, GoodsStatus.SHELVED);
        return Response.buildSuccess();
    }

    /**
     * 下架商品 - 事务脚本实现方式
     *
     * @param goodsIds 商品ID列表
     * @return 响应结果
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Response unshelveGoods(List<Long> goodsIds) {
        //批量更新商品状态为已下架
        this.goodsRepository.batchModifyGoodsStatus(goodsIds, GoodsStatus.UNSHELVED);
        return Response.buildSuccess();
    }
}
